/**
*	Header: common.h
*	
*	This header contains functions, global variables and whatever needed that is commonly used
*	by several files or do not belong in any other cpp-h file pair.
*	
*/

#pragma once

#include <vector>
#include <list>
#include <iostream>
#include <string>
#include "object.h"

#define GAME_NAME "Roguelike"
#define VERSION_NUMBER "v0.3.0"

class Actor;

namespace gameSettings {
	unsigned short windowX = 80; // Window width in tiles
	unsigned short windowY = 50; // Window width in tiles
	unsigned short maxFPS = 0; // Uncapped at 0
	bool fullscreen = false;
	bool showMouse = true;
};

struct Tile { // Could use std::bitset to reduce memory needed for each tile
	Tile() {
		c = 0;
		foreColour = TCODColor::black;
		backColour = TCODColor::black;
		passable = true;
		transparent = true;
	}

	char c;
	TCODColor foreColour; // TODO: Generalise colour variable to renderer-agnostic uint8 triplet
	TCODColor backColour;
	bool passable;
	bool transparent;

	// These std::lists form the bulk of tile memory use. Optimise somehow.
	std::list <Actor*> actorList; //Actors on tile
	std::list <Item*> itemList;
};

class TileMap {
public:
	TileMap ();

	TileMap (const unsigned int x, const unsigned int y);

	~TileMap();

	Tile* const getTile(const unsigned int x, const unsigned int y);

	TCODMap* const getTCODMap() {return fovMap;}

	const unsigned int getWidth() {return width;}

	const unsigned int getHeight() {return height;}

	// Call to update FOV map
	void update();

	void computeFov(unsigned int playerX,unsigned int playerY,unsigned int maxRadius=0,bool light_walls = true, TCOD_fov_algorithm_t algo = FOV_BASIC);

	bool isInFov(int x, int y) const;

	void resizeMap (const unsigned int x, const unsigned int y);

private:
	unsigned int width;
	unsigned int height;
	std::vector<Tile> map; // Note: Under def. constructor this is uninitialised.
	TCODMap* fovMap;
};

TileMap::TileMap () {
	std::cerr << "WARNING: Map width and height not set. Defaulting to window size.\n";
	width = gameSettings::windowX;
	height = gameSettings::windowY;
	map.resize(width*height);
	fovMap = new TCODMap(width,height);
}

TileMap::TileMap (const unsigned int x, const unsigned int y) {
	width = x;
	height = y;
	map.resize(width*height);
	fovMap = new TCODMap(width,height);
}

TileMap::~TileMap() {
	delete fovMap;
}

Tile* const TileMap::getTile(const unsigned int x, const unsigned int y) {
	if ((x >= width)||(x < 0)) {
		std::cerr << "ERROR: TileMap.getTile(" << x << "," << y << ") width out of range.\n";
		return &Tile();
	}
	if ((y >= height)||(y < 0)) {
		std::cerr << "ERROR: TileMap.getTile(" << x << "," << y << ") width out of range.\n";
		return &Tile();
	}
	else return &map[x + (y * width)];
}

void TileMap::update() {
	for(unsigned int y = 0; y < height; y++) {
		for(unsigned int x = 0; x < width; x++) {
			fovMap->setProperties(x,y,getTile(x,y)->transparent,getTile(x,y)->passable);
		}
	}
}

void TileMap::computeFov(unsigned int playerX,unsigned int playerY,unsigned int maxRadius, bool light_walls, TCOD_fov_algorithm_t algo) {
	fovMap->computeFov(playerX,playerY,maxRadius,light_walls,algo);
}

bool TileMap::isInFov(int x, int y) const {
	return fovMap->isInFov(x, y);
}

void TileMap::resizeMap (const unsigned int x, const unsigned int y) {
	width = x;
	height = y;
	map.resize(width*height); // fills vector with black, transparent, passable tiles
	delete fovMap;
	fovMap = new TCODMap(width,height);
	update();
}